package com.xiyu.service.service.office;

import com.xiyu.service.vo.office.building.BuildingSimpleUnitGetOutput;
import com.xiyu.service.vo.office.building.BuildingSimpleFloorGetOutput;
import com.xiyu.service.vo.office.building.BuildingSingleGetOutput;
import com.xiyu.service.model.office.building.OfficeBuildingFloor;
import com.xiyu.service.repository.office.building.OfficeBuildingFloorRepository;
import com.xiyu.service.model.office.building.OfficeBuildingUnit;
import com.xiyu.service.repository.office.building.OfficeBuildingUnitRepository;
import com.xiyu.service.vo.office.building.BuildingUpdateInput;
import com.xiyu.service.model.office.building.OfficeBuildingProps;
import com.xiyu.service.model.office.building.OfficeBuildingDraft;
import com.xiyu.service.vo.office.building.BuildingCreateInput;
import com.xiyu.service.model.office.building.OfficeBuilding;
import com.xiyu.service.repository.office.building.OfficeBuildingRepository;
import com.xiyu.service.vo.office.building.BuildingPageQueryOutput;
import com.xiyu.service.vo.office.building.BuildingPageQueryInput;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.babyfish.jimmer.Page;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

import com.xiyu.service.util.entity.EntityUtils;
import org.babyfish.jimmer.DraftObjects;
import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.convert.office.BuildingConvert;

import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.errorCode.office.BuildingErrorCode.*;

/**
 * 办公楼管理 Service 实现类
 */
@Service
@Validated
public class BuildingServiceImpl implements BuildingService {

    @Resource
    private OfficeBuildingFloorRepository officeBuildingFloorRepository;

    @Resource
    private OfficeBuildingUnitRepository officeBuildingUnitRepository;

    @Resource
    private OfficeBuildingRepository officeBuildingRepository;




    @Override
    public PageResult<BuildingPageQueryOutput> pageQuery(BuildingPageQueryInput inputVO) {
        Page<OfficeBuilding> pageOfficeBuilding = officeBuildingRepository.pageQuery(inputVO);
        List<BuildingPageQueryOutput> listOfficeBuilding = BuildingConvert.INSTANCE.pageQueryOutputConvert(pageOfficeBuilding.getRows());
        return new PageResult<>(listOfficeBuilding, pageOfficeBuilding.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(BuildingCreateInput inputVO) {
        OfficeBuilding newOfficeBuilding = BuildingConvert.INSTANCE.createInputConvert(inputVO);
        newOfficeBuilding = officeBuildingRepository.insert(newOfficeBuilding);
        return newOfficeBuilding.id();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(BuildingUpdateInput inputVO) {
        Optional<OfficeBuilding> optionalOldOfficeBuilding = officeBuildingRepository.findById(inputVO.getId());
        if(!optionalOldOfficeBuilding.isPresent()){
            throw exception(OFFICE_BUILDING_NOT_EXIST);
        }
        for(BuildingUpdateInput.buildingFloor buildingFloor : inputVO.getBuildingFloors().stream().
                sorted(Comparator.comparing(BuildingUpdateInput.buildingFloor::getOperateType)).collect(Collectors.toList())){
            if(Objects.equals(buildingFloor.getOperateType(), "delete")){
                Optional<OfficeBuildingFloor> optionalDeleteOfficeBuildingFloor = officeBuildingFloorRepository.findById(buildingFloor.getId());
                if(!optionalDeleteOfficeBuildingFloor.isPresent()){
                    throw exception(OFFICE_BUILDING_UNIT_NOT_EXIST);
                }
                officeBuildingFloorRepository.deleteById(buildingFloor.getId());
            }else if(Objects.equals(buildingFloor.getOperateType(), "new")){
                OfficeBuildingFloor newOfficeBuildingFloor = BuildingConvert.INSTANCE.updateInputConvert(buildingFloor);
                officeBuildingFloorRepository.insert(newOfficeBuildingFloor);
            }else{
                Optional<OfficeBuildingFloor> optionalOldOfficeBuildingFloor = officeBuildingFloorRepository.findById(buildingFloor.getId());
                if(!optionalOldOfficeBuildingFloor.isPresent()) {
                    throw exception(OFFICE_BUILDING_UNIT_NOT_EXIST);
                }
                OfficeBuildingFloor updateOfficeBuildingFloor = BuildingConvert.INSTANCE.updateInputConvert(buildingFloor);
                if (!EntityUtils.isEquals(optionalOldOfficeBuildingFloor.get(), updateOfficeBuildingFloor))
                    officeBuildingFloorRepository.update(updateOfficeBuildingFloor);
            }
        }

        for(BuildingUpdateInput.buildingUnit buildingUnit : inputVO.getBuildingUnits().stream()
                .sorted(Comparator.comparing(BuildingUpdateInput.buildingUnit::getOperateType)).collect(Collectors.toList())){
            if(Objects.equals(buildingUnit.getOperateType(), "delete")){
                Optional<OfficeBuildingUnit> optionalDeleteOfficeBuildingUnit = officeBuildingUnitRepository.findById(buildingUnit.getId());
                if(!optionalDeleteOfficeBuildingUnit.isPresent()){
                    throw exception(OFFICE_BUILDING_UNIT_NOT_EXIST);
                }
                officeBuildingFloorRepository.deleteById(buildingUnit.getId());
            }else if(Objects.equals(buildingUnit.getOperateType(), "new")){
                OfficeBuildingUnit newOfficeBuildingUnit = BuildingConvert.INSTANCE.updateInputConvert(buildingUnit);
                officeBuildingUnitRepository.insert(newOfficeBuildingUnit);
            }else{
                Optional<OfficeBuildingUnit> optionalOldOfficeBuildingUnit = officeBuildingUnitRepository.findById(buildingUnit.getId());
                if(!optionalOldOfficeBuildingUnit.isPresent()) {
                    throw exception(OFFICE_BUILDING_UNIT_NOT_EXIST);
                }
                OfficeBuildingUnit updateOfficeBuildingUnit = BuildingConvert.INSTANCE.updateInputConvert(buildingUnit);
                if (!EntityUtils.isEquals(optionalOldOfficeBuildingUnit.get(), updateOfficeBuildingUnit))
                    officeBuildingUnitRepository.update(updateOfficeBuildingUnit);
            }
        }
        OfficeBuilding updateOfficeBuilding = BuildingConvert.INSTANCE.updateInputConvert(inputVO);
        updateOfficeBuilding = OfficeBuildingDraft.$.produce(updateOfficeBuilding, draft -> {
            DraftObjects.unload(draft, OfficeBuildingProps.BUILDING_UNITS);
            DraftObjects.unload(draft, OfficeBuildingProps.BUILDING_FLOORS);
        });
        if (!EntityUtils.isEquals(optionalOldOfficeBuilding.get(), updateOfficeBuilding))
            officeBuildingRepository.update(updateOfficeBuilding);
        return true;
    }

    @Override
    public BuildingSingleGetOutput singleGet(Long id) {
        Optional<OfficeBuilding> optionOfficeBuilding = officeBuildingRepository.findDetailById(id);
        if(!optionOfficeBuilding.isPresent()){
            throw exception(OFFICE_BUILDING_NOT_EXIST);
        }
        return BuildingConvert.INSTANCE.singleGetOutputConvert(optionOfficeBuilding.get());

    }

    @Override
    public List<BuildingSimpleFloorGetOutput> simpleFloorGet(Long id) {
        return BuildingConvert.INSTANCE.simpleFloorGetOutputConvert(officeBuildingFloorRepository.findByBuildingId(id));
    }

    @Override
    public List<BuildingSimpleUnitGetOutput> simpleUnitGet(Long id) {
        return BuildingConvert.INSTANCE.simpleUnitGetOutputConvert(officeBuildingUnitRepository.findByBuildingId(id));
    }

}
